<template>
  <view
    class="aster-switch"
    :class="props.disabled && 'aster-switch--disabled'"
    :style="switchStyle"
    @tap="clickHandler"
  >
    <view class="aster-switch__bg" :style="bgStyle" />
    <view
      class="aster-switch__node"
      :class="props.value && 'aster-switch__node--on'"
      :style="nodeStyle"
      ref="aster-switch__node"
    />
  </view>
</template>
<script setup lang="ts">
  import { addUnit } from '@/utils';
  import { computed, nextTick } from 'vue';

  const props = defineProps({
    // 是否为禁用装填
    disabled: {
      type: Boolean,
      default: () => false,
    },
    // 开关尺寸，单位rpx
    size: {
      type: Number,
      default: () => 50,
    },
    // 打开时的背景颜色
    activeColor: {
      type: String,
      default: () => '#2979ff',
    },
    // 关闭时的背景颜色
    inactiveColor: {
      type: String,
      default: () => '#e6e6e6',
    },
    // 通过v-model双向绑定的值
    value: {
      type: [Boolean, String, Number],
      default: () => false,
    },
    // switch打开时的值
    activeValue: {
      type: [String, Number, Boolean],
      default: () => true,
    },
    // switch关闭时的值
    inactiveValue: {
      type: [String, Number, Boolean],
      default: () => false,
    },
    // 是否开启异步变更，开启后需要手动控制输入值
    asyncChange: {
      type: Boolean,
      default: () => false,
    },
    // 圆点与外边框的距离
    space: {
      type: Number,
      default: () => 0,
    },
  });

  const emits = defineEmits(['input', 'change']);

  const switchStyle = computed(() => {
    let style: any = {};
    // 这里需要加2，是为了腾出边框的距离，否则圆点node会和外边框紧贴在一起
    style.width = addUnit(props.size * 2 + 2);
    style.height = addUnit(Number(props.size) + 2);
    // style.borderColor = this.value ? 'rgba(0, 0, 0, 0)' : 'rgba(0, 0, 0, 0.12)'
    // 如果自定义了“非激活”演示，name边框颜色设置为透明(跟非激活颜色一致)
    // 这里不能简单的设置为非激活的颜色，否则打开状态时，会有边框，所以需要透明
    if (props.inactiveColor !== '#fff' && props.inactiveColor !== '#ffffff') {
      style.borderColor = 'rgba(0, 0, 0, 0)';
    }
    style.backgroundColor =
      props.value === props.activeValue ? props.activeColor : props.inactiveColor;
    return style;
  });
  const nodeStyle = computed(() => {
    let style: any = {};
    // 如果自定义非激活颜色，将node圆点的尺寸减少两个像素，让其与外边框距离更大一点
    style.width = addUnit(props.size - props.space);
    style.height = addUnit(props.size - props.space);
    const translateX =
      props.value === props.activeValue ? addUnit(props.space) : addUnit(props.size);
    style.transform = `translateX(-${translateX})`;
    return style;
  });
  const bgStyle = computed(() => {
    let style: any = {};
    // 这里配置一个多余的元素在HTML中，是为了让switch切换时，有更良好的背景色扩充体验(见实际效果)
    style.width = addUnit(Number(props.size) * 2 - props.size / 2);
    style.height = addUnit(props.size);
    style.backgroundColor = props.inactiveColor;
    // 打开时，让此元素收缩，否则反之
    style.transform = `scale(${props.value === props.activeValue ? 0 : 1})`;
    return style;
  });

  const clickHandler = () => {
    if (!props.disabled) {
      const oldValue = props.value === props.activeValue ? props.inactiveValue : props.activeValue;
      if (!props.asyncChange) {
        emits('input', oldValue);
      }
      // 放到下一个生命周期，因为双向绑定的value修改父组件状态需要时间，且是异步的
      nextTick(() => {
        emits('change', oldValue);
      });
    }
  };
</script>
<style lang="scss" scoped>
  view,
  scroll-view,
  swiper-item {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    flex-grow: 0;
    flex-basis: auto;
    align-items: stretch;
    align-content: flex-start;
  }

  .aster-switch {
    display: flex;
    flex-direction: row;
    /* #ifndef APP-NVUE */
    box-sizing: border-box;
    /* #endif */
    position: relative;
    background-color: #fff;
    border-width: 1px;
    border-radius: 100px;
    transition: background-color 0.4s;
    border-color: rgba(0, 0, 0, 0.12);
    border-style: solid;
    justify-content: flex-end;
    align-items: center;
    // 由于weex为阿里逗着玩的KPI项目，导致bug奇多，这必须要写这一行，
    // 否则在iOS上，点击页面任意地方，都会触发switch的点击事件
    overflow: hidden;

    &__node {
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      border-radius: 100px;
      background-color: #fff;
      border-radius: 100px;
      box-shadow: 1px 1px 1px 0 rgba(0, 0, 0, 0.25);
      transition-property: transform;
      transition-duration: 0.4s;
      transition-timing-function: cubic-bezier(0.3, 1.05, 0.4, 1.05);
    }

    &__bg {
      position: absolute;
      border-radius: 100px;
      background-color: #ffffff;
      transition-property: transform;
      transition-duration: 0.4s;
      border-top-left-radius: 0;
      border-bottom-left-radius: 0;
      transition-timing-function: ease;
    }

    &--disabled {
      opacity: 0.6;
    }
  }
</style>
